// CSE 532 Lab 2 Fall 2006 Provided Code: Socket Input Iterator
// Authors: Venkita Subramonian and Chris Gill

#include <iostream>
#include <iterator>
#include "ace/SOCK_Stream.h"
#include "ace/Log_Msg.h"

#include "globals.h"
#include "io-manager.h"

using namespace std;

// Forward declaration of class template
template <typename T> class isock_stream_iterator;

// Non-member-function declaration for equivalence operator
template <typename T>
bool operator==(const isock_stream_iterator<T>& x,
		const isock_stream_iterator<T>& y);

// Non-member-function declaration for non-equivalence operator
template <typename T>
bool operator!=(const isock_stream_iterator<T>& x,
		const isock_stream_iterator<T>& y);

template <typename T> 
class isock_stream_iterator {

  // Friend declarations to give explicit access to class members

  friend bool operator==<> (const isock_stream_iterator&,
			    const isock_stream_iterator&);

  friend bool operator!=<> (const isock_stream_iterator&,
			    const isock_stream_iterator&);

protected:

  // The ACE socket that acts as a container for the iterator
  ACE_SOCK_Stream* sock_stream_;

  // Flag for off-the-end iterator position
  bool eof_;

  // Variable for the most recent value read from the socket
  T value_;

  // Helper method to read data from the socket into the 
  void sock_read() {

    if (sock_stream_ == 0) {
      cout << "Socket iterator pointer is 0" << endl;
      return;
    }

    // This is a blocking read, which should be decoupled from
    // the current thread of execution, either by handing it off to an
    // active object that can perform the blocking read in its own
    // thread of execution, or by handing off the data to an object with
    // reactive concurrency (in a separate reactor thread from the thread
    // that calls this operator) that (1) stores a pointer to a
    // buffer into which the info should be read (for example treating
    // the parameterized variable type as though it were a character
    // array), (2) maintains a pointer that marks how many bytes of the
    // buffer have been read in so far, and (3) does a single recv
    // each time it's called and updates the progress pointer, until there
    // are no more bytes to receive.
    int ret_val = sock_stream_->recv_n(&value_, sizeof(T));
    if (ret_val) {
      IOManager::instance()->read_data = true;
    }
    if (DEBUG) std::cout << "Read " << ret_val << " bytes " << value_ << std::endl;
    if ( !eof_ && (ret_val <= 0))
      {
		eof_ = true;
      }
    else if (value_ == 0) {
      // If T is NULL, then we can stop reading because we've received one
      // "message".
      eof_ = true;
    }
  }

public:

  // Traits for the iterator
  typedef input_iterator_tag  iterator_category;
  typedef T                 value_type;
  typedef ptrdiff_t         difference_type;
  typedef const T*          pointer;
  typedef const T&          reference;

  // Default constructor used to create an off-the-end iterator
  isock_stream_iterator() : sock_stream_(0), eof_(true){}
  
  // Constructor used to create a dereferencable iterator
  isock_stream_iterator(ACE_SOCK_Stream& s) : 
     sock_stream_(&s), eof_(false) { sock_read(); }

  // Pointer dereference operator
  reference operator*() const { return value_; }

  // Prefix increment operator: increments and then returns state of iterator
  isock_stream_iterator<T>& operator++() { 

    sock_read(); 
    return *this;
  }

  // Postfix increment operator: saves state of iterator, increments
  // and then returns saved state
  isock_stream_iterator<T> operator++(int)  {

    isock_stream_iterator<T> tmp = *this;

    sock_read();
    return tmp;
  }
};

// Non-member-function declaration for equivalence operator
template <typename T>
  inline bool operator==(const isock_stream_iterator<T>& x,
			 const isock_stream_iterator<T>& y) {

  // Iterators are equivalent either if they reference the same socket
  // and have the same eof state, or if they're both at eof.
  return ((x.sock_stream_ == y.sock_stream_ && x.eof_ == y.eof_) || 
          (x.eof_ == true && y.eof_ == true));
}

// Non-member-function declaration for non-equivalence operator
template <typename T>
  inline bool operator!=(const isock_stream_iterator<T>& x,
			 const isock_stream_iterator<T>& y) {
  return !(x == y);
}
